package com.zzb.spring.aop.impl.xml;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.sun.corba.se.spi.orbutil.fsm.Guard.Result;

/**
 * 日志切面：由多个日志切点组成（前置日志和后置为两个切点）
 * 
 * 1. 加入jar包 com.springsource.net.sf.cglib-2.2.0.jar
 * com.springsource.org.aopalliance-1.0.0.jar
 * com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
 * spring-aspects-4.0.0.RELEASE.jar
 * 
 * 2. 在 Spring 的配置文件中加入 aop 的命名空间。
 * 
 * 3. 基于注解的方式来使用 AOP 3.1 在配置文件中配置自动扫描的包:
 * <context:component-scan base-package="com.atguigu.spring.aop">
 * </context:component-scan> 3.2 加入使 AspjectJ 注解起作用的配置:
 * <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 为匹配的类自动生成动态代理对象.
 * 
 * 4. 编写切面类: 4.1 一个一般的 Java 类 4.2 在其中添加要额外实现的功能.
 *
 * 5. 配置切面 5.1 切面必须是 IOC 中的 bean: 实际添加了 @Component 注解 5.2 声明是一个切面: 添加 @Aspect
 * 5.3 声明通知: 即额外加入功能对应的方法. 5.3.1 前置通知: @Before(
 * "execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(int, int))"
 * )
 * 
 * @Before 表示在目标方法执行之前执行 @Before 标记的方法的方法体.
 * @Before 里面的是切入点表达式:
 * 
 *         6. 在通知中访问连接细节: 可以在通知方法中添加 JoinPoint 类型的参数, 从中可以访问到方法的签名和方法的参数.
 * 
 *         7. @After 表示后置通知: 在方法执行之后执行的代码.
 * 
 */

// 把这个类声明为一个切面；需要把该类放入到IOC容器中，再声明为一个切面
//@Order(2) 指定切面优先级  值越小优先级越高
public class LoggingAspect {

	// 声明该方法时一个前置通知，在目标方法开始之前执行 *号表示所有方法
	// 需要在applicationContext中增加 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
	// 需要使在目标方法被调用之前生成一个代理对象
	public void beforeMethod(JoinPoint joinPoint) {
		// joinPoint表示连接点：程序执行的某个特定位置
		String methodName = joinPoint.getSignature().getName();
		Object[] args = joinPoint.getArgs();

		System.out.println("The method " + methodName + " begins with " + Arrays.asList(args));
	}

	/*
	 * 在方法执行之后执行的代码，无论该方法是否出现异常
	 */
	// * 代表匹配任意修饰符及任意返回值; , 参数列表中的 .. 匹配任意数量的参数
	public void afterMethod(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println("The method " + methodName + " ends");
	}

	/*
	 * 返回通知
	 * 在方法 正常结束 目标的代码 后调用 返回通知是可以访问到方法的返回值
	 */
	public void afterReturnMethod(JoinPoint joinPoint, Object result) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println("The method " + methodName + " ends with " + result);
	}

	/*
	 * 异常通知
	 * 在目标方法出现异常时，会执行的代码
	 * 可以访问到异常对象，可以指定特定异常的对象Exception
	 */
	public void afterThrowMethod(JoinPoint joinPoint, Exception ex) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println("The method " + methodName + " occurs  excetion: " + ex);
	}
	
	/*
	 * 环绕通知，需要携带ProceedingJoinPoint类型的参数
	 * 环绕通知，类似于动态代理的全过程：ProceedingJoinPoint类型的参数可以决定是否执行目标方法
	 * 必须有返回值，返回值为目标方法的返回值
	 * 功能最全
	 */
	
	/*
	@Around("VlidationAspect.declareJointPointExpression()") //引用另一个类中的切入点表达式
//	@Around("execution(* com.zzb.spirng.aop.impl.*.*(..))")
	public Object aroundMethod(ProceedingJoinPoint pjd) {
		
		Object result = null;
		String methodName = pjd.getSignature().getName();
		//执行目标方法
		try {
			//前置通知
			System.out.println("环绕通知The methos " + methodName + " begin with " + Arrays.asList(pjd.getArgs()));
			result = pjd.proceed();
			//返回通知
			System.out.println("环绕通知The method " + methodName + " ends with " + result);
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			//异常通知
			System.out.println("环绕通知The method " + methodName + " occurs  excetion: " + e);
			e.printStackTrace();
		}
		//后置通知
		System.out.println("环绕通知The method " + methodName + " ends ");
		return result;
	}
	*/
}
